package com.vf.admin.client.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vf.admin.client.common.RedisKeys;
import com.vf.admin.client.controller.pay.wechatpay.JsApiConstants;
import com.vf.admin.client.dao.WechatPayConfigsDao;
import com.vf.admin.client.result.PayInfoResult;
import com.vf.admin.client.service.AppOrderService;
import com.vf.admin.client.service.VipOrderService;
import com.vf.admin.client.service.WechatPayConfigsService;
import com.vf.admin.common.Constants;
import com.vf.admin.common.redis.RedisUtil;
import com.vf.admin.miaodong.entity.*;
import com.vf.admin.utils.pay.ApiAplayWeChat.IpUtils;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.*;

import static com.vf.admin.utils.RandomUtil.getOrderIdByUUId;

/**
 * <p>Title : </p>
 * <p>Description : </p>
 * <p>DevelopTools : IDEA</p>
 * <p>DevelopSystem : Windows10</p>
 *
 * @Author : NemoMeng
 * @Date 2023/6/26 11:30
 */
@Service
public class WechatPayConfigsImpl implements WechatPayConfigsService {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private WechatPayConfigsDao wechatPayConfigsDao;
    //钱包订单
    @Autowired
    private AppOrderService appOrderService;
    //vip订单
    @Autowired
    private VipOrderService vipOrderService;


    public WechatPayConfigs getWeightPlayInfo() {
        List<WechatPayConfigs> wechatPayConfigs = null;
        if (!redisUtil.hasKey(RedisKeys.WECHATCONFIGS)) {
            wechatPayConfigs = wechatPayConfigsDao.list();
            redisUtil.set(RedisKeys.WECHATCONFIGS, wechatPayConfigs, RedisKeys.ALICONFIGSOUTTIME);
        } else {
            wechatPayConfigs = (List<WechatPayConfigs>) redisUtil.get(RedisKeys.WECHATCONFIGS);
        }
        Integer sumWeight = 0;//总权重的值
        JSONArray as = new JSONArray();//存入对象用于概率
        Integer index = 0;
        for (int i = 0; i < wechatPayConfigs.size(); i++) {
            Integer weight = wechatPayConfigs.get(i).getWeight();
            if (weight > 0) {
                sumWeight = sumWeight + weight;
                for (int j = 0; j < weight; j++) {
                    as.add(index, wechatPayConfigs.get(i));
                    index++;//放后面保证0也有值
                }
            }
        }
        Integer r = new Random().nextInt(sumWeight + 1);//随机数生成概率
        WechatPayConfigs wechatPayConfigs1 = (WechatPayConfigs) as.get(r);
        System.out.println("权重：" + wechatPayConfigs1);
        return (WechatPayConfigs) as.get(r);
    }

    /**
     * 如果你是使用Apache HttpClient的商户开发者，可以使用它构造HttpClient。得到的HttpClient在执行请求时将自动携带身份认证信息，并检查应答的微信支付签名。
     */
    private static CloseableHttpClient httpClient = null;


    /**
     * 初始化
     */
    public void setup(WechatPayConfigs weightPlayInfo) {

        // 加载商户私钥（privateKey：私钥字符串）
        PrivateKey merchantPrivateKey = null;
        try {
            merchantPrivateKey = PemUtil
                    .loadPrivateKey(new ByteArrayInputStream(weightPlayInfo.getPrivateKey().getBytes("utf-8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
        AutoUpdateCertificatesVerifier verifier = null;
        try {
            verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(weightPlayInfo.getMchId(), new PrivateKeySigner(weightPlayInfo.getMchSerialNo(), merchantPrivateKey)),
                    weightPlayInfo.getApiKey().getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        // 初始化httpClient
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(weightPlayInfo.getMchId(), weightPlayInfo.getMchSerialNo(), merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }


    @Override
    public PayInfoResult wechatDiamondRechargeH5(HttpServletRequest request, AppUser user, AppCzMoney czMoney, String mobileSpec) {
        //权重
        WechatPayConfigs weightPlayInfo = getWeightPlayInfo();
        //初始化商户连接
        setup(weightPlayInfo);
        //添加订单记录
        AppOrder appOrder = new AppOrder();
        appOrder.setCreatetime(new Date());
        appOrder.setOrdernum(getOrderIdByUUId());//生成订单号
        appOrder.setCzMoneyId(czMoney.getId());
        appOrder.setMoney(new BigDecimal(czMoney.getMoney()));
        appOrder.setStatus(Constants.dingdan_status_dfk);//默认  1、代付款 2、已付款
        appOrder.setType(Constants.dingdan_zhiFuLeiXing_wx); //订单支付类型  默认 1、支付宝 2、微信 3、苹果  4、杉德支付宝 5、杉德微信
        appOrder.setUserid(user.getId());//下单人信息
        appOrder.setPic(user.getPic());
        appOrder.setNick(user.getNick());
        appOrder.setPhone(user.getLoginname());
        appOrder.setNum(czMoney.getDiamonds().add(czMoney.getGive()));
        appOrder.setMobileSpec(mobileSpec);
        appOrderService.save(appOrder);
        //金额
        int total = appOrder.getMoney().multiply(new BigDecimal(100)).intValue();//单位是分
//        int total = 1;//单位是分

        //获取ip地址
        String ipAddr = IpUtils.getRealIp(request);
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5");
        String notify_url = weightPlayInfo.getNotifyUrl() + "/" + weightPlayInfo.getAppId();
        // 请求body参数
        String reqdata = "{"
                + "\"amount\": {"
                + "\"total\": " + total + ","
                + "\"currency\": \"CNY\""
                + "},"
                + "\"scene_info\": {"
                + "\"payer_client_ip\":\"" + ipAddr + "\","
                + "\"h5_info\": {"
                + "\"type\": \"Android\"" + "}},"
                + "\"mchid\": \"" + weightPlayInfo.getMchId() + "\","
                + "\"description\":\"钻石充值\","
                + "\"notify_url\": \"" + notify_url + "\","
                + "\"out_trade_no\": \"" + appOrder.getOrdernum() + "\","
                + "\"appid\": \"" + weightPlayInfo.getAppId() + "\"" + "}";

        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        PayInfoResult payInfoResult = new PayInfoResult();
        String signMap = "";
        try {
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    signMap = EntityUtils.toString(response.getEntity());
                } else if (statusCode == 204) {
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }

            } finally {
                response.close();
            }
            JSONObject jsonObject = JSON.parseObject(signMap);
            String h5_url = jsonObject.get("h5_url").toString();
            payInfoResult.setOrderNo(appOrder.getOrdernum());
            payInfoResult.setPayUrl(h5_url);
            return payInfoResult;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public PayInfoResult wechatOpenVipRechargeH5(HttpServletRequest request, AppUser user, VipPackage vipPackage, String mobileSpec) {
        //权重
        WechatPayConfigs weightPlayInfo = getWeightPlayInfo();
        //初始化商户连接
        setup(weightPlayInfo);
        //添加订单记录
        VipOrder vipOrder = new VipOrder();
        vipOrder.setUserId(user.getId());
        vipOrder.setOrderNo(getOrderIdByUUId());//订单号
        vipOrder.setVipPackageId(vipPackage.getId());//
        vipOrder.setStatus(0);  //0待支付 1已支付
        vipOrder.setPayType("weixinPay");
        vipOrder.setCreateTime(new Date());
        vipOrder.setType(Constants.dingdan_zhiFuLeiXing_wx); //订单支付类型  默认 1、支付宝 2、微信 3、苹果  4、杉德支付宝 5、杉德微信
        vipOrder.setMobileSpec(mobileSpec);
        vipOrder.setNick(user.getNick());
        vipOrder.setPhone(user.getLoginname());
        vipOrder.setPrice(vipPackage.getPrice());
        vipOrder.setPic(user.getPic());
        vipOrderService.save(vipOrder);
        //金额
        int total = vipPackage.getPrice().multiply(new BigDecimal(100)).intValue();//单位是分
//        int total = 1;//单位是分

        //获取ip地址
        String ipAddr = IpUtils.getRealIp(request);
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5");
        // 请求body参数
        String notify_url = weightPlayInfo.getVipNotifyUrl() + "/" + weightPlayInfo.getAppId();
        String reqdata = "{"
                + "\"amount\": {"
                + "\"total\": " + total + ","
                + "\"currency\": \"CNY\""
                + "},"
                + "\"scene_info\": {"
                + "\"payer_client_ip\":\"" + ipAddr + "\","
                + "\"h5_info\": {"
                + "\"type\": \"Android\"" + "}},"
                + "\"mchid\": \"" + weightPlayInfo.getMchId() + "\","
                + "\"description\":\"会员充值\","
                + "\"notify_url\": \"" + notify_url + "\","
                + "\"out_trade_no\": \"" + vipOrder.getOrderNo() + "\","
                + "\"appid\": \"" + weightPlayInfo.getAppId() + "\"" + "}";

        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        PayInfoResult payInfoResult = new PayInfoResult();
        String signMap = "";


        try {
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    signMap = EntityUtils.toString(response.getEntity());
                } else if (statusCode == 204) {
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }

            } finally {
                response.close();
            }
            JSONObject jsonObject = JSON.parseObject(signMap);
            String h5_url = jsonObject.get("h5_url").toString();
            payInfoResult.setOrderNo(vipOrder.getOrderNo());
            payInfoResult.setPayUrl(h5_url);
            return payInfoResult;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public PayInfoResult shopH5(HttpServletRequest request, String name, BigDecimal price) {
        //权重
        WechatPayConfigs weightPlayInfo = getWeightPlayInfo();
        //初始化商户连接
        setup(weightPlayInfo);
        //金额
        int total = price.multiply(new BigDecimal(100)).intValue();//单位是分
        String orderIdByUUId = getOrderIdByUUId();
        //获取ip地址
        String ipAddr = IpUtils.getRealIp(request);
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5");
        // 请求body参数
        String notify_url = weightPlayInfo.getVipNotifyUrl() + "/" + weightPlayInfo.getAppId();
        String reqdata = "{"
                + "\"amount\": {"
                + "\"total\": " + total + ","
                + "\"currency\": \"CNY\""
                + "},"
                + "\"scene_info\": {"
                + "\"payer_client_ip\":\"" + ipAddr + "\","
                + "\"h5_info\": {"
                + "\"type\": \"Android\"" + "}},"
                + "\"mchid\": \"" + weightPlayInfo.getMchId() + "\","
                + "\"description\":\"商品购买\","
                + "\"notify_url\": \"" + notify_url + "\","
                + "\"out_trade_no\": \"" + orderIdByUUId + "\","
                + "\"appid\": \"" + weightPlayInfo.getAppId() + "\"" + "}";

        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        PayInfoResult payInfoResult = new PayInfoResult();
        String signMap = "";


        try {
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    signMap = EntityUtils.toString(response.getEntity());
                } else if (statusCode == 204) {
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }

            } finally {
                response.close();
            }
            JSONObject jsonObject = JSON.parseObject(signMap);
            String h5_url = jsonObject.get("h5_url").toString();
            payInfoResult.setOrderNo(orderIdByUUId);
            payInfoResult.setPayUrl(h5_url);
            return payInfoResult;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public WechatPayConfigs getAppIdInfo(String appIdStr) {

        return wechatPayConfigsDao.getAppIdInfo(appIdStr);
    }


    @Override
    public Map<String, String> jsApiDiamondRecharge(
            HttpServletRequest request,
            AppUser user,
            AppCzMoney czMoney,
            String mobileSpec,
            String openid) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        //添加订单记录
        AppOrder appOrder = new AppOrder();
        appOrder.setCreatetime(new Date());
        appOrder.setOrdernum(getOrderIdByUUId());//生成订单号
        appOrder.setCzMoneyId(czMoney.getId());
        appOrder.setMoney(BigDecimal.valueOf(czMoney.getMoney()));
        appOrder.setStatus(Constants.dingdan_status_dfk);//默认  1、代付款 2、已付款
        appOrder.setType(Constants.dingdan_zhiFuLeiXing_wx); //订单支付类型  默认 1、支付宝 2、微信 3、苹果  4、杉德支付宝 5、杉德微信
        appOrder.setUserid(user.getId());//下单人信息
        appOrder.setPic(user.getPic());
        appOrder.setNick(user.getNick());
        appOrder.setPhone(user.getLoginname());
        appOrder.setNum(czMoney.getDiamonds().add(czMoney.getGive()));
        appOrder.setMobileSpec(mobileSpec);
        appOrderService.save(appOrder);
        //金额
        int total = appOrder.getMoney().multiply(new BigDecimal(100)).intValue();//单位是分
        // 请求body参数
        JSONObject order = new JSONObject();
        //应用ID
        order.put("appid", JsApiConstants.APP_ID);
        //商户号
        order.put("mchid", JsApiConstants.MCH_ID);
        // 商品描述
        order.put("description", "商品购买");
        // 订单号
        order.put("out_trade_no", appOrder.getOrdernum());
        // 通知地址
        order.put("notify_url", JsApiConstants.NOTIFY_URL);
        /*订单金额*/
        JSONObject amount = new JSONObject();
        amount.put("total", total);
        // 货币类型
        amount.put("currency", "CNY");
        order.put("amount", amount);
        /*支付者*/
        JSONObject payer = new JSONObject();
        // 用户标识
        payer.put("openid", openid);
        order.put("payer", payer);
        //初始化连接
        initCertificatesJsApi();
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setEntity(new StringEntity(order.toJSONString(), "UTF-8"));
        String signMap = "";

        try {
            //完成签名并执行请求
            CloseableHttpResponse response = httpClientJs.execute(httpPost);
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
                    signMap = EntityUtils.toString(response.getEntity());
                } else if (statusCode == 204) {
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }

            } finally {
                response.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = JSON.parseObject(signMap);
        // 时间戳
        String timeStamp = String.valueOf(System.currentTimeMillis());
        // 随机字符串
        String nonceStr = UUID.randomUUID().toString();
        //package
        String prepayId = "prepay_id=" + jsonObject.get("prepay_id");
        //signType
        String signType = "RSA";
        //paySign

        Signature signature = Signature.getInstance("SHA256withRSA");
        String sb = JsApiConstants.APP_ID + "\n" + //小程序appId
                timeStamp + "\n" + //时间戳
                nonceStr + "\n" + //随机字符串
                prepayId + "\n";//订单详情扩展字符串

        // 从证书管理器中获取verifier
        PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(JsApiConstants.PRIVATE_KEY.getBytes(StandardCharsets.UTF_8)));
        signature.initSign(privateKey);
        signature.update(sb.getBytes(StandardCharsets.UTF_8));
        String paySign = Base64.getEncoder().encodeToString(signature.sign());

        Map<String, String> map = new HashMap<>();
        map.put("appId", JsApiConstants.APP_ID);
        map.put("timeStamp", timeStamp);
        map.put("nonceStr", nonceStr);
        map.put("package", prepayId);
        map.put("signType", signType);
        map.put("paySign", paySign);

        return map;
    }

    /**
     * 如果你是使用Apache HttpClient的商户开发者，可以使用它构造HttpClient。得到的HttpClient在执行请求时将自动携带身份认证信息，并检查应答的微信支付签名。
     */
    private static CloseableHttpClient httpClientJs = null;

    public void initCertificatesJsApi() {

        // 加载商户私钥（privateKey：私钥字符串）
        PrivateKey merchantPrivateKey = null;
        merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(JsApiConstants.PRIVATE_KEY.getBytes(StandardCharsets.UTF_8)));

        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
        AutoUpdateCertificatesVerifier verifier = null;
        verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(JsApiConstants.MCH_ID, new PrivateKeySigner(JsApiConstants.MCH_SERIAL_NO, merchantPrivateKey)),
                JsApiConstants.API_V3_KEY.getBytes(StandardCharsets.UTF_8));

        // 初始化httpClient
        httpClientJs = WechatPayHttpClientBuilder.create()
                .withMerchant(JsApiConstants.MCH_ID, JsApiConstants.MCH_SERIAL_NO, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }




}
